
#include "Ymodem.h"


#if		YMODEM_RECV_ENABLE == 1	


/*************************************************************
  Function   : YModem_RecvPacket 
  Description: 接收一个数据包
  Input      : buff-存放接收到的数据 
               length-数据包的长度
			          timeout-超时时间       
  return     : 0 	正常接收  
			   -1 	接收错误 
			   -2	用户接收终止
			   -3	收到接收终止字符
*************************************************************/
int YModem_RecvPacket(unsigned char *buff,unsigned int *length, unsigned int timeout)
{
	unsigned int i, packet_size;
	unsigned char  c;

	*length = 0;
	if(YModem_RecvByte(&c, timeout))//接收数据包的第一个字节
	{
		return -1;
	}
	switch(c)
	{
	case SOH:				//128字节数据包
			packet_size = PACKET_SIZE;		//记录数据包的长度
			break;
	case STX:				//1024字节数据包
			packet_size = PACKET_1K_SIZE;	//记录数据包的长度
			break;
	case EOT:				//数据接收结束字符
			return 0; 		//接收结束			 
	case CA:				//接收中止标志
			if((YModem_RecvByte(&c, timeout) == 0) && (c == CA))//等待接收中止字符
			{
				//接收到中止字符
				return -3;					 
			}else							//接收超时
			{
				return -1;
			}
	case ABORT1:			//用户终止，用户按下'A'
	case ABORT2:			//用户终止，用户按下'a'
			return -2;                       //接收终止
	default:
			return -1;                      //接收错误
	}

	*buff = c;	                //保存第一个字节
	for(i = 1; i < (packet_size + PACKET_OVERHEAD); i++)//接收数据
	{
		if(YModem_RecvByte(buff + i, timeout) )
		{
			return -1;
		}
	}
	//包序号检查	
	if(buff[PACKET_SEQNO_INDEX] != ((buff[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff))
	{
		return -1;                   //包序号接收错误	
	}
	//CRC检查
	i = W_CRC16(&buff[PACKET_HEADER] , packet_size);

	//
	*length = packet_size;               //保存接收到的数据长度
	return 0;                            //正常接收
}

/*************************************************************
  Function   : YModem_Receive 
  Description: ymodem接收
  Input      : buf-存放接收到的数据 
			   length 接收数据的总长度
  return     : 
				
				0 -发送端传输中止
               -1 -固件过大
			   -2 -flash烧写错误
			   -3 -用户终止    
*************************************************************/
int YModem_Receive_Proc(unsigned char *buf, unsigned int *length)
{
	unsigned int		i,size;	
	unsigned int  		errors; 	
	unsigned int		packets_received;
	unsigned int 		packet_length;		
	unsigned int		app_bin_datalen;
	
	unsigned char  		*file_ptr, *buf_ptr;

	*length = 0;
	size = 0;
	errors = 0;
	
	packets_received = 0;		
	
	app_bin_datalen = 0;
	buf_ptr = buf;
	memset(buf_ptr,0xff,FLASH_PAGE_SIZE);//
		
	while(1)	//死循环，不断接收数据
	{
		switch(YModem_RecvPacket(packet_data, &packet_length, NAK_TIMEOUT))//接收数据包
		{
			case 0:	//接收正常					
				errors = 0;
				if(packet_length)//接收数据中
				{						
					if((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) 
					{
						//接收错误的数据，回复NAK
						YModem_SendByte(NAK);
					}else	
					{
						if(packets_received == 0)//接收第一帧数据
						{
							if(packet_data[PACKET_HEADER] != 0)//包含文件信息：文件名，文件长度等
							{
								for(i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH); )
								{
									if(i < 16)	file_name[i++] = *file_ptr++;//保存文件名
									else
									{	
										file_name[i++] = '\0';		//文件名以'\0'结束 
										file_ptr++;	
									}
								}
								file_name[i++] = '\0';//文件名以'\0'结束 	
								for(i = 0, file_ptr++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH); )
								{
									file_size[i++] = *file_ptr++;//保存文件大小
								}
								file_size[i++] = '\0';//文件大小以'\0'结束 													
								size = w_atoi((char *)file_size);//将文件大小字符串转换成整型
								*length = size;
								if(UpdateAppCodeStart(file_name, size))	//
								{
									YModem_SendByte(CA);			 
									YModem_SendByte(CA);//连续发送2次中止符CA
									return -1;//返回
								}
								size = 0;
								YModem_SendByte(ACK);	//回复ACk
								YModem_SendByte(CRC16);//发送'C',询问数据
							}
							else//文件名数据包为空，结束传输
							{
								YModem_SendByte(ACK);//回复ACK
								return 0;
							}
						}else 
						{
							file_ptr = packet_data + PACKET_HEADER;	
							while(packet_length)
							{
								if(packet_length >= (FLASH_PAGE_SIZE - app_bin_datalen))
								{
									memcpy(buf_ptr + app_bin_datalen, file_ptr, (FLASH_PAGE_SIZE - app_bin_datalen));//拷贝数据
									file_ptr += (FLASH_PAGE_SIZE - app_bin_datalen);
									packet_length -= (FLASH_PAGE_SIZE - app_bin_datalen);
									//接收到1页固件资料，就更新写入
									if(UpdateAppCode(buf_ptr))
									{
										YModem_SendByte(CA);	 
										YModem_SendByte(CA);//flash烧写错误，连续发送2次中止符CA
										return -2;//烧写错误
									}
									size += FLASH_PAGE_SIZE;
									app_bin_datalen = 0;
									memset(buf_ptr,0xff,FLASH_PAGE_SIZE);	
								}else
								{
								 	memcpy(buf_ptr + app_bin_datalen, file_ptr, packet_length);//拷贝数据
									app_bin_datalen += packet_length;
									packet_length = 0;
								}
							}									
							YModem_SendByte(ACK);//flash烧写成功，回复ACK
						}
						packets_received++;//收到数据包的个数
					}						
				}else
				{
					YModem_SendByte(ACK);
					//接收完成	
					UpdateAppCodeEnd(buf_ptr, app_bin_datalen);
					size += app_bin_datalen;
					return size;
				}
				break;
					
			case -2:		                //用户中止
				YModem_SendByte(CA);
				YModem_SendByte(CA);    //连续发送2次中止符CA
				return -3;		//烧写中止
				
			case -3:
				//发送端中止传输
				YModem_SendByte(ACK);//回复ACK
				return 0;
			
			case -1:
				if(packets_received > 0)   //传输过程中发生错误
				{
					errors++;
					if(errors > MAX_ERRORS) //错误超过上限
					{
						YModem_SendByte(CA);
						YModem_SendByte(CA);//连续发送2次中止符CA
						return 0;	//传输过程发生过多错误
					}						
				}
				YModem_SendByte(CRC16); //发送'C',继续接收
				break;
		} 
	}
}

#endif

